import re
from datetime import datetime
from typing import Type, Optional

from pydantic import BaseModel, ConfigDict, create_model
from pydantic.alias_generators import to_camel
from sqlalchemy import Column, String, DateTime, Integer
from sqlalchemy.orm import DeclarativeBase, declared_attr
from sqlalchemy.sql.schema import ScalarElementColumnDefault

from config.env import DataBaseConfig


class CBase(DeclarativeBase):
    __table_args__ = {
        "mysql_engine": "InnoDB",  # MySQL引擎
        "mysql_charset": "utf8mb4",  # 设置表的字符集
        "mysql_collate": "utf8mb4_general_ci",  # 设置表的校对集
        # "mysql_comment": "表名备注",  # 设置表名备注
    } if DataBaseConfig.db_type == "mysql" else {}

    @declared_attr.directive
    def __tablename__(cls) -> str:
        snake_case = re.sub(r"(?P<key>[A-Z])", r"_\g<key>", cls.__name__)
        return snake_case.lower().strip('_')

    @classmethod
    def model_fields_set(cls):
        return [f.name for f in cls.__table__.columns]


class TBase:
    create_by = Column(String(64), nullable=True, default='', comment='创建者')
    create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间')
    update_by = Column(String(64), nullable=True, default='', comment='更新者')
    update_time = Column(DateTime, nullable=True, onupdate=datetime.now(), default=datetime.now(), comment='更新时间')
    remark = Column(String(500), nullable=True, default='', comment='备注')


class IDBase:
    id = Column(Integer, primary_key=True, autoincrement=True, comment='参数主键')


DO_PRIMARY_KEY = {}


class AutoConfigModel(BaseModel):
    model_config = ConfigDict(alias_generator=to_camel, from_attributes=True)


class PageQueryModel(BaseModel):
    page_size: int = 10
    page_num: int = 1
    sort: str = ''


def sqlalchemy_to_pydantic(model: Type[CBase]):
    dynamic_fields, ext_fields = {}, {}
    name = model.__name__
    a: ScalarElementColumnDefault
    for f in model.__table__.columns:
        if f.primary_key: DO_PRIMARY_KEY[name] = f.name
        dynamic_fields[f.name] = (Optional[f.type.python_type], None)
        if f.type.python_type == datetime:
            ext_fields['begin_' + f.name] = (Optional[f.type.python_type], None)
            ext_fields['end_' + f.name] = (Optional[f.type.python_type], None)

    pydantic_model = create_model(name + 'Model', __base__=AutoConfigModel, **dynamic_fields)
    pydantic_qry_model = create_model(name + 'QueryModel', __base__=pydantic_model, **ext_fields)

    return pydantic_model, pydantic_qry_model
